import { IPublicTypeJSExpression, IPublicTypeJSFunction } from '@alilc/lowcode-types';
import { camelCase, pascalCase as _upperCaseFirst, paramCase } from 'change-case';
import short from 'short-uuid';
import { DependencyType, IDependency, IExternalDependency, IInternalDependency } from '../types';

// Doc: https://www.npmjs.com/package/change-case

export function camel2dash(input: string): string {
  return paramCase(input);
}

/**
 * 转为驼峰
 */
export function camelize(str: string): string {
  return camelCase(str);
}

export function generateID(): string {
  return short.generate();
}

export function upperCaseFirst(inputValue: string): string {
  return _upperCaseFirst(inputValue);
}

export function uniqueArray<T>(arr: T[], by: (i: T) => string) {
  const map: Record<string, T> = {};
  arr.forEach((item) => {
    map[by(item)] = item;
  });
  // FIXME: Babel 编译存在问题，暂时替换实现
  // const uniqueKeys = [...new Set<string>(Object.keys(map))];
  const uniqueKeys = Array.from(new Set<string>(Object.keys(map)));
  const uniqueItems = uniqueKeys.map((key) => map[key]);
  return uniqueItems;
}

export function getStaticExprValue<T>(expr: string): T {
  try {
    // 检查表达式中是否包含循环变量引用（如item、index等）
    // 如果包含，则直接返回原始表达式，不进行求值
    const possibleLoopVars = ['item', 'index'];
    const hasLoopVars = possibleLoopVars.some((varName) => {
      const pattern = new RegExp(`\\b${varName}\\b`, 'g');
      return pattern.test(expr);
    });

    // 检查表达式中是否包含箭头函数
    const hasArrowFunction = expr.includes('=>');

    if (hasLoopVars || hasArrowFunction) {
      // 对于包含循环变量或箭头函数的表达式，直接返回原始表达式
      return expr as unknown as T;
    }

    // 对于不包含循环变量的表达式，进行正常求值
    const context = { state: {}, props: {}, utils: {} };
    return Function('state', 'props', 'utils', `"use strict";return (${expr})`).call(
      context,
      context.state,
      context.props,
      context.utils,
    );
  } catch (e) {
    // 如果求值失败，返回原始表达式
    console.warn('表达式求值失败，返回原始表达式:', expr, e);
    return expr as unknown as T;
  }
}

export function isJSExpressionFn(data: any): data is IPublicTypeJSFunction {
  return data?.type === 'JSExpression' && data?.extType === 'function';
}

export function isInternalDependency(dependency: IDependency): dependency is IInternalDependency {
  return dependency.dependencyType === DependencyType.Internal;
}

export function isExternalDependency(dependency: IDependency): dependency is IExternalDependency {
  return dependency.dependencyType === DependencyType.External;
}
